package com.llbnk.springcoding.thread;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;

/**
 * @author llbnk
 */
@Slf4j
public class ThreadExcutorWrapper implements  ExecutorService{

    /**
     * self-define params
     */
    private final ThreadExcutorConfig threadExcutorConfig;
    /**
     * thread pool name
     */
    private final String poolName;

    /**
     * real-use ExecutorService
     */
    private final ExecutorService executorService;

    public ThreadExcutorWrapper(ThreadExcutorConfig threadExcutorConfig,String poolName,ExecutorService executorService) {
        this.threadExcutorConfig = threadExcutorConfig;
        this.poolName = poolName;
        this.executorService = executorService;
    }

    @Override
    public void shutdown() {
        //1.没有自定义配置直接使用默认关闭线程池方法
        if (Objects.isNull(this.threadExcutorConfig)) {
            this.executorService.shutdown();
            return;
        }
        //2.判断是否需要马上关闭线程池
        if (!this.threadExcutorConfig.isWaitForTasksToComplete()) {
            this.executorService.shutdown();
        } else {
            this.executorService.shutdownNow();
        }
        /*
         * 3.如果配置等待时间，则判断超过等待时间中断该任务
         * show case；假设用此线程池下载资源此时没有配置3waitForTasksToComplete
         * 就会走shutdown()方法，用户想取消下载，但是shutdown方法仅仅不在接受新任务老任务一样处理，
         * 此时只要配置awaitTerminationSeconds,就会在一定时间之后挂起该任务
         */
        if(this.threadExcutorConfig.getAwaitTerminationSeconds() > 0){
            try {
                boolean isClose = executorService.awaitTermination(
                        this.threadExcutorConfig.getAwaitTerminationSeconds(), TimeUnit.SECONDS);
                if(isClose){
                    // add log or monitor
                    log.info("thread pool shutdown sucess, pool name:{}",this.poolName);
                }
            } catch (InterruptedException e) {
                // add log or monitor
                log.warn("thread pool shutdown interrupt, pool name:{}",this.poolName);
                Thread.currentThread().interrupt();
            }
        }
    }

    @Override
    public List<Runnable> shutdownNow() {
        return this.executorService.shutdownNow();
    }

    @Override
    public boolean isShutdown() {
        return this.executorService.isShutdown();
    }

    @Override
    public boolean isTerminated() {
        return this.executorService.isTerminated();
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return this.executorService.awaitTermination(timeout,unit);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return this.executorService.submit(task);
    }

    @Override
    public <T> Future<T> submit(Runnable task, T result) {
        return this.executorService.submit(task,result);
    }

    @Override
    public Future<?> submit(Runnable task) {
        return this.executorService.submit(task);
    }

    @Override
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
        return this.executorService.invokeAll(tasks);
    }

    @Override
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
        return this.executorService.invokeAll(tasks,timeout,unit);
    }

    @Override
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
        return this.executorService.invokeAny(tasks);
    }

    @Override
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        return this.executorService.invokeAny(tasks,timeout,unit);
    }

    @Override
    public void execute(Runnable command) {
        this.executorService.execute(command);
    }


    public ThreadExcutorConfig getThreadExcutorConfig() {
        return threadExcutorConfig;
    }

    public String getPoolName() {
        return poolName;
    }

    public ExecutorService getExecutorService() {
        return executorService;
    }
}
